home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / nasanets.zip / PARSER.C < prev    next >
C/C++ Source or Header  |  1990-06-07  |  57KB  |  1,366 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Construction Of Net Structures (Prefix = PS_)
  19. ----------------------------------------------------------------------
  20.   This code is divided into 4 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions
  24.   (3) global variables
  25.   (4) subroutines
  26.  
  27.   Each section is further explained below.
  28. ----------------------------------------------------------------------
  29. */
  30.  
  31.  
  32. /*
  33. ----------------------------------------------------------------------
  34.   INCLUDE FILES
  35. ----------------------------------------------------------------------
  36. */
  37. #include "common.h"
  38. #include "netio.h"
  39.  
  40.  
  41. /*
  42. ----------------------------------------------------------------------
  43.   MACRO DEFINITIONS
  44. ----------------------------------------------------------------------
  45.   Below are eight different macros used for range checking while the
  46.   network spec file is being parsed. Each commands in the file takes
  47.   a numeric argument, and these macros can check ranges for any of the
  48.   eight possible cases given an upper bound (u) and a lower bound (l)
  49.   on the number "n". 
  50. ----------------------------------------------------------------------
  51. */
  52. #define GTLT(n,l,u)  (((n) >  (l) && (n) <  (u)) ? 1 : 0)
  53. #define GELT(n,l,u)  (((n) >= (l) && (n) <  (u)) ? 1 : 0)
  54. #define GTLE(n,l,u)  (((n) >  (l) && (n) <= (u)) ? 1 : 0)
  55. #define GELE(n,l,u)  (((n) >= (l) && (n) <= (u)) ? 1 : 0)
  56.  
  57. #define LTGT(n,l,u)  (((n) <  (l) || (n) >  (u)) ? 1 : 0)
  58. #define LEGT(n,l,u)  (((n) <= (l) || (n) >  (u)) ? 1 : 0)
  59. #define LTGE(n,l,u)  (((n) <  (l) || (n) >= (u)) ? 1 : 0)
  60. #define LEGE(n,l,u)  (((n) <= (l) || (n) >= (u)) ? 1 : 0)
  61.  
  62.  
  63. /*
  64. ----------------------------------------------------------------------
  65.   EXTERNED FUNCTIONS AND GLOBALS
  66. ----------------------------------------------------------------------
  67.   Below are the functions defined in other files which are used by the
  68.   code here. They are organized by section.
  69. ----------------------------------------------------------------------
  70. */
  71. extern Sint      C_float_to_Sint();
  72. extern char     *sys_alloc();
  73. extern FILE     *PA_open_binary();
  74. extern int       PA_put_to_workfile();
  75. extern void      PA_flush();
  76. extern void      IO_print();
  77.  
  78. extern char      IO_str[MAX_LINE_SIZE];
  79.  
  80.  
  81. /*
  82. ----------------------------------------------------------------------
  83.   GLOBAL VARIABLES
  84. ----------------------------------------------------------------------
  85.   First, some markers which are used by several routines and are just
  86.   declared here a globals for convenience. A parsing variable is next,
  87.   called "use_last_command" which is needed for the parsing of layer
  88.   specifications. It determines whether or not to reuse the last 
  89.   command read in during the parsing. Then come two globals which are
  90.   used during the creation of a network to indicate whether or not a
  91.   global learning rate and/or momentum has been used. If so, then these
  92.   two globals will contain the floating point equivalent of the given
  93.   values.
  94. ----------------------------------------------------------------------
  95. */
  96. static int     line_count = 1;   /* used by parse_iopairs, PS_get_token */
  97. static char    last_char;        /* holds the last character read in    */
  98. static char    last_str[MAX_LINE_SIZE];   /* holds last command read in */
  99. static int     use_last_command = FALSE;  /* used for layer parse (see  */
  100.                                           /* PS_get_command).           */
  101. float          global_learn_base;   /* used during parse to set default */
  102. float          global_momentum;     /* global learn/momentum values     */
  103.  
  104.  
  105. /*
  106. ======================================================================
  107.   ROUTINES IN PARSER.C                                                   
  108. ======================================================================
  109.   The routines in this file are grouped below by function.  Each routine
  110.   is prefixed by the string "PS_" indicating that it is defined in the 
  111.   "parser.c" file.  The types returned by the routines are also shown 
  112.   here so that cross checking is more easily done between these functions
  113.   and the other files which intern them.
  114.  
  115.  
  116.   Type Returned                 Routine                                 
  117.   -------------                 -------                                 
  118.     void                        PS_reset_for_layer_parse
  119.     int                         PS_global_spec_check
  120.     Layer_spec *                PS_get_layer
  121.     void                        PS_get_learn_values
  122.     void                        PS_get_nodes
  123.     void                        PS_get_node_dimensions
  124.     void                        PS_get_target
  125.     void                        PS_get_pattern
  126.     int                         PS_get_command
  127.     void                        PS_print_command
  128.     int                         PS_range_check
  129.     int                         PS_int_check
  130.     int                         PS_parse_iopairs
  131.     int                         PS_check_items
  132.     int                         PS_skip_tokens
  133.     int                         PS_get_token
  134.     int                         PS_get_float_from_file
  135. ======================================================================
  136. */
  137.  
  138.  
  139. void  PS_reset_for_layer_parse()
  140. /*
  141. ----------------------------------------------------------------------
  142.   The only thing done here, as of now, is to set the global variable
  143.   'use_last_command' to FALSE. This must be done from the OUTSIDE via
  144.   this routine because the global is static to this file.
  145. ----------------------------------------------------------------------
  146. */
  147. BEGIN
  148.    use_last_command = FALSE;
  149.  
  150. END /* PS_reset_for_layer_parse */
  151.  
  152.  
  153. int  PS_global_spec_check(ptr_file)
  154. FILE  *ptr_file;
  155. /*
  156. ----------------------------------------------------------------------
  157.  This routine checks for the existence of two optional specs located 
  158.   at the very beginning of a network specification file. They are the
  159.   GLOBAL-LEARN-RATE and GLOBAL-MOMENTUM respectively. Either or both
  160.   of these may be specified by the user. If they are present, they 
  161.   define default values for the learn_base and momemtum elements of 
  162.   each layer. These values may be overridden later by using the 
  163.   LEARN-RATE, SCALE-FACTOR, or MOMENTUM commands for each layer which
  164.   needs overriding.
  165.   
  166.   Returns ERROR if EOF encountered while trying to check for these 
  167.   first two optional commands.
  168. ----------------------------------------------------------------------
  169. */
  170. BEGIN
  171.    float  num;
  172.    int    temp, PS_get_command(), PS_range_check();
  173.    void   PS_print_command();
  174.    
  175.    /*--------------------------------------*/
  176.    /* first, set the global values to -1.0 */
  177.    /* symbolizing UNKNOWN values           */
  178.    /*--------------------------------------*/
  179.    global_learn_base = UNDEFINED;
  180.    global_momentum   = UNDEFINED;
  181.    
  182.    /*-----------------------------------*/
  183.    /* loop on PS_get_command, until you */
  184.    /* hit EOF or a LAYER command.       */
  185.    /*-----------------------------------*/
  186.    temp = PS_get_command(ptr_file, &num);
  187.    while (temp != LAYER) BEGIN
  188.       if (temp == EOF) BEGIN
  189.          sprintf(IO_str, "\n*** ERROR: no specifications found in file");
  190.          IO_print(0);
  191.          return(ERROR);
  192.       ENDIF
  193.       else if (temp == GLOBAL_LEARN_RATE) BEGIN
  194.          if (PS_range_check( GTLE(num, 0, LEARN_MAX) ) == OK)
  195.             global_learn_base = num;
  196.       ENDELSE
  197.       else if (temp == GLOBAL_MOMENTUM) BEGIN
  198.          if (PS_range_check( GELE(num, 0, MOMENTUM_MAX) ) == OK)
  199.             global_momentum = num;
  200.       ENDELSE
  201.       else BEGIN
  202.          sprintf(IO_str, "\n*** WARNING: spurious ");
  203.          IO_print(0);
  204.          PS_print_command(temp);
  205.          sprintf(IO_str, " command found before LAYER specification.");
  206.          IO_print(0);
  207.          sprintf(IO_str, "\nCommand ignored.");
  208.          IO_print(0);
  209.       ENDELSE
  210.       temp = PS_get_command(ptr_file, &num);
  211.    ENDWHILE
  212.    
  213.    /*-----------------------------------*/
  214.    /* set USE_LAST_COMMAND flag to TRUE */
  215.    /*-----------------------------------*/
  216.    use_last_command = TRUE;
  217.    return(OK);
  218.  
  219. END /* PS_global_spec_check */
  220.  
  221.  
  222. Layer_spec  *PS_get_layer(ptr_file)
  223. FILE  *ptr_file;
  224. /*
  225. ----------------------------------------------------------------------
  226.  This routine reads lines from the file pointed to by 'ptr_file' and  
  227.   converts them into the 'Layer_spec' format described in the file    
  228.   'netio.h'.  Now, to understand how this is done, you must know the  
  229.   the specifics of how the file is set up.  In a sense, the logic of  
  230.   this routine describes that setup.  In conjunction with the def-    
  231.   inition of 'Layer_spec', that setup is described here.              
  232.  First, an example of what ONE layer specification might look like in 
  233.   a file:                                                             
  234.                                                                       
  235.    LAYER : 25         -- comment for line 1                           
  236.    NODES : 5          -- comment for line 2                           
  237.                       -- line 2 comment continued                     
  238.      TARGET : 2                                                       
  239.      TARGET : 4                                                       
  240.      TARGET : 6                                                       
  241.                                                                       
  242.   notice that the first two lines have comments (those comments would 
  243.   not necessarily appear in the file; they are here as an example     
  244.   only).  There are several important features I would point out in   
  245.   this example.  First, note that a Layer specification consists of   
  246.   three types of commands:  ONE "layer", ONE "nodes" and some (optional)
  247.   number of "target" commands.  The layer command specifies the ID
  248.   number which will be assigned to the layer.  The nodes command 
  249.   indicates the number of nodes contained in the layer.  The target         
  250.   commands (of which there may be zero!) denote the OTHER layers to   
  251.   which this layer has OUTGOING connections. For example, the layer   
  252.   above, layer 25, has 3 outgoing connections to layers 2, 4, and 6   
  253.   respectively.  This also means that these three layers have incoming
  254.   weights from layer 25 (see Layer structure definition in layer.h);
  255.   but NOTE THAT THOSE LAYERS WOULD NOT NEED TARGET SPECIFICATIONS. Only
  256.   the layer acting as a SOURCE needs to have the target specification.
  257.   Putting the specification in both places is redundant and more 
  258.   difficult on the user. 
  259.  A couple of notes about how this routine reads the input file. First 
  260.   note that each of the commands above looks like "command : number"  
  261.   THE SPACES HERE ARE SIGNIFICANT.  This routine does a pattern match 
  262.   rather than a sophisticated scanning, so if you leave the spaces out
  263.   you get an error.  Also, note that the comments have "--" in front  
  264.   of them.  This is not necessary, but it is a good idea.  The reason 
  265.   lies in the fact that EACH LINE MUST HAVE AT MOST ONE COMMAND and   
  266.   THAT COMMAND MUST NOT BE PRECEDED BY ANY OTHER TEXT.  Thus, if you  
  267.   had a comment that ran over one line, and which also happened to    
  268.   include something that looked like a command syntax, it could be    
  269.   interpreted as a command.  To avoid this, always preceed any        
  270.   comments with the double dash.
  271.  
  272.   To summarize the input file syntax:
  273.  
  274.     each line must have AT MOST one command
  275.     commands look like "command : number"; SPACES ARE SIGNIFICANT
  276.     comments should be preceeded by a double dash: ie "--"
  277.     layer connections are specified from SOURCE LAYER ONLY
  278.     LAYER and NODES commands are essential for a layer, TARGET is optional
  279. ----------------------------------------------------------------------
  280.   4-7-88  I've added a new twist to the layer specification to allow for
  281.   PATTERNED CONNECTION schemes between layers, in addition to the fully
  282.   connected scheme already available. Here's the deal. Imagine that you
  283.   have two layers, one of which is larger than the other. Let's call them
  284.   layer B (Big) and layer L (Little). You might be in a position where
  285.   you did NOT want all of the nodes of layer B to be connected to all
  286.   of the nodes in layer L. One reason might be that there would simply 
  287.   be two many connections. A more plausible reason might be that you 
  288.   only want LOCAL ASSOCIATIONS between layer B and layer S. That is, you
  289.   might want groups of nodes in layer B which are "close together" to 
  290.   map to a single node in layer L. This is often the case with nets which
  291.   are attempting to work with visual input. Often, one tries to associate
  292.   small areas of the input layer (usually a screen image) and map them to
  293.   separate nodes of a hidden layer. In this way, one simulates "piecing
  294.   together" the bits of visual information on the screen by trying to 
  295.   build larger and larger primitive shapes (line, curve, angle, etc) out
  296.   of small regions of the image. Anyway, the point is, you might want to
  297.   have some pattern of connections between layer B and L, and I have added
  298.   syntax to allow for that.
  299.   OK, first things first. Assume two layers B and L where nodes(B) > nodes(L)
  300.   (B has more nodes). Assume further that the dimensions of B are UxV (in the 
  301.   X and Y dimensions respectively) and those of L are MxN.  Now, one can 
  302.   define "Pattern areas" of layer B which are to be mapped as a group 
  303.   onto SINGLE nodes of L. Let this "pattern area" be of dimension PxQ 
  304.   (also in terms of X,Y). Finally, one might imagine that these pattern 
  305.   areas overlap with eachother (why not?) and this overlap may occur in
  306.   either, or both, the X and Y dimensions. Let this overlap be defined
  307.   as RxS (X overlap = R, Y overlap = S). Here's and example:
  308.  
  309.   Layer B:          _______
  310.                    |0|1|2|3|       UxV = 4x2
  311.                    |4|5|6|7|       12 nodes, numbered 0-C
  312.                    |8|A|B|C|
  313.                     -------
  314.  
  315.   Pattern area:     _____
  316.                    |_|_|_|         PxQ = 3x2
  317.                    | | | |         Overlap 2 in the X direction, 1 in the Y
  318.                     -----            so RxS = 2x1
  319.  
  320.   with the above specifications, lets walk through how layer L would have 
  321.   to look. The first pattern area would start at node 0 of B and go 3 in 
  322.   X direction, and 2 in the Y direction.  This would involve nodes 0, 1, 2
  323.   and 4, 5, 6 of layer B. This area would map to the first node of layer L.
  324.   The second pattern area STARTS AT NODE 1 OF LAYER B!!! This is because the
  325.   user specified an overlap of 2 in the X direction. Thus the second pattern
  326.   area covers nodes 1, 2, 3 and 5, 6, 7 of layer B. The third pattern area
  327.   is now found by moving DOWN (in the Y direction) and since the user 
  328.   specified a Y overlap of 1, the third pattern area STARTS AT NODE 4 of B.
  329.   This area covers nodes 4,5,6 and 8,A,B of layer B. Finally, the last
  330.   pattern area again overlaps 2 in the X direction and covers nodes 5,6,7
  331.   and A,B,C.  Layer L then has only 4 nodes as follows:
  332.  
  333.   Layer L:          ___
  334.                    |0|1|           Mxn = 2x2
  335.                    |2|3|           4 nodes, numbered 0-3
  336.                     ---
  337.  
  338.   In all, 24 weights are needed. That is, 4 pattern areas, each with a
  339.   3x2 area mapped to 1 node = 3 * 2 * 4 or 6 * 4 = 24. The following is
  340.   a list of weights and the nodes which each connects:
  341.  
  342.   Weight number           Node in B         Node in L
  343.   -------------           ---------         ---------
  344.        0                      0                 0
  345.        1                      1                 0
  346.        2                      2                 0
  347.        3                      4                 0
  348.        4                      5                 0
  349.        5                      6                 0
  350.  
  351.        6                      1                 1
  352.        7                      2                 1
  353.        8                      3                 1
  354.        9                      5                 1
  355.       10                      6                 1
  356.       11                      7                 1
  357.  
  358.       12                      4                 2
  359.       13                      5                 2
  360.       14                      6                 2
  361.       15                      8                 2
  362.       16                      9                 2
  363.       17                      A                 2
  364.  
  365.       18                      5                 3
  366.       19                      6                 3
  367.       20                      7                 3
  368.       21                      A                 3
  369.       22                      B                 3
  370.       23                      C                 3
  371.  
  372.   SYNTAX: The new syntax has all the same rules as the old plus the 
  373.   following:
  374.   (1) X and Y dimensions are specified separately
  375.   (2) dimensions not specified for the layer will default
  376.   (3) if No dimension is specified for NODES, then the layer is
  377.       assumed to be X = NODES, Y = 1.
  378.   (4) if only one dimension is missing, it is assumed = 1.
  379.   (5) pattern areas are defined along with the TARGET command
  380.   (6) only the overlap specs are optional for a pattern specification.
  381.       These X and Y dimensions MUST be specified. If no overlaps are
  382.       specified, they will default to 0.
  383.   (7) if TARGET specs do not include dimensions, a CONNECT ALL scheme
  384.       is assumed.
  385.  
  386.   EXAMPLE: To generate the net above (say there were only two 
  387.   layers) we would do:
  388.  
  389.   LAYER : 0                  -- only one command per line
  390.   NODES : 12                 -- spacing only significant around ":'s"
  391.     X-DIMENSION : 4          -- optional dimensions 
  392.     Y-DIMENSION : 3
  393.     TARGET : 1
  394.       PATTERN-X-DIMENSION : 3  -- optional. If not present, then
  395.       PATTERN-Y-DIMENSION : 2  -- "connect all" is assumed.
  396.       X-OVERLAP : 2
  397.       Y-OVERLAP : 1
  398.  
  399.   LAYER : 1
  400.   NODES : 4
  401.     X-DIMENSION : 2          -- a good idea to specify both layer's
  402.     Y-DIMENSION : 2          -- dimensions since system will verify.
  403.  
  404.   Note that the dimensions of BOTH layers will, in general, have to be
  405.   specified as the system will check to see that the dimensions are 
  406.   correct for the given pattern area dimension/overlap specification.
  407.  
  408.   The full BNF for the layer spec syntax is ("{}" indicate optional,
  409.   and commands are in all caps):
  410.  
  411.   layer-spec   :== LAYER  node-spec  {target-spec}
  412.   node-spec    :== NODES  {X-DIMENSION}  {Y-DIMENSION}
  413.   target-spec  :== TARGET  {pattern-spec} {target-spec}
  414.   pattern-spec :== PATTERN-X-DIMENSION  PATTERN-Y-DIMENSION  {X-OVERLAP}
  415.                    {Y-OVERLAP}
  416. ----------------------------------------------------------------------
  417.   5-3-89 Im adding another piece of syntax to the net specification file
  418.    which will be optional. I want the user to be able to specify the
  419.    learning rate, scaling factor, and momentum in the file so that 
  420.    delivery networks can be easily created. This will also allow for
  421.    automatic generation of network specification files from a simple
  422.    list of IO pairs. The new syntax lookes like:
  423.    
  424.    node-spec   :== NODES {dimensions} {l-factors}
  425.    dimensions  :== X-DIMENSION {dimensions} | Y-DIMENSION {dimensions}
  426.    l-factors   :== LEARN-RATE {l-factors} | SCALE-FACTOR {l-factors}
  427.                    | MOMENTUM {l-factors}
  428.                    
  429.    i.e., any or all of the three learning constants may be entered 
  430.    after the optional x,y dimension info. Also, I have changed the
  431.    syntax to allow for global specification of the learning rate and
  432.    momentum. These parameters are considered optional, before the
  433.    specification of the layers in the network, as the BNF below shows
  434.    (see PS_global_spec_check and B_process_config):
  435.    
  436.    network     :== {globals} layer-spec layer-spec {hiddens}
  437.    globals     :== GLOBAL-LEARN-RATE {globals}
  438.                    | GLOBAL-MOMENTUM {globals}
  439.    hiddens     :== layer-spec {hiddens}
  440. ----------------------------------------------------------------------
  441. */
  442. BEGIN
  443.    Layer_spec  *result;
  444.    float       num;
  445.    int         temp, PS_get_command(), PS_range_check(), PS_int_check();
  446.    void        PS_get_nodes(), PS_get_target(), PS_print_command(),
  447.                PS_get_learn_values();
  448.  
  449.    /*----------------------------*/
  450.    /* start out as a good layer  */
  451.    /*----------------------------*/
  452.    result = (Layer_spec *) sys_alloc((unsigned)sizeof(Layer_spec));
  453.    result->status = OK;                      
  454.  
  455.    /*------------------------------*/
  456.    /* read until good layer or EOF */
  457.    /*------------------------------*/
  458.    temp = PS_get_command(ptr_file, &num);
  459.    while (TRUE) BEGIN
  460.       if (temp == EOF) BEGIN
  461.          result->status = EOF;
  462.          break;
  463.       ENDIF
  464.       if ( (temp == LAYER)
  465.            && (PS_int_check(num) == OK)
  466.            && (PS_range_check(GELE(num, 0, MAX_LAYERS)) == OK) ) 
  467.          break;
  468.       sprintf(IO_str, "\n*** WARNING: spurious ");
  469.       IO_print(0);
  470.       PS_print_command(temp);
  471.       sprintf(IO_str, " command found outside of LAYER specification.");
  472.       IO_print(0);
  473.       sprintf(IO_str, "\nCommand ignored.");
  474.       IO_print(0);
  475.       temp = PS_get_command(ptr_file, &num);
  476.    ENDWHILE
  477.  
  478.    /*---------------------------------------------*/
  479.    /* once you have a layer, read its nodes specs */
  480.    /*---------------------------------------------*/
  481.    if (result->status == OK) BEGIN
  482.       result->ID = (int)num;
  483.       
  484.       /*-------------------------------------------*/
  485.       /* look for any learning rate specifications */
  486.       /*-------------------------------------------*/
  487.       PS_get_learn_values(ptr_file, result);
  488.  
  489.       PS_get_nodes(ptr_file, result);
  490.    ENDIF
  491.    
  492.    /*----------------------------*/
  493.    /* then read the target specs */
  494.    /*----------------------------*/
  495.    if (result->status == OK)
  496.       PS_get_target(ptr_file, result);
  497.       
  498.    /*-------------------------------------*/
  499.    /* if delivery code is being run, then */
  500.    /* get the learning values from the    */
  501.    /* arrays defined in the delivery file */
  502.    /*-------------------------------------*/
  503. #if  DELIVERY
  504.    result->learn_base  = 0;
  505.    result->learn_scale = 0;
  506.    result->momentum    = 0;
  507. #endif
  508.       
  509.    /*-------------------------------------------------*/
  510.    /* if any errors occur, print message, then return */
  511.    /*-------------------------------------------------*/
  512.    if (result->status == ERROR) BEGIN
  513.       sprintf(IO_str, "\n\n*** ERROR: Problems in Net Specification file");
  514.       IO_print(0);
  515.    ENDIF
  516.    return(result);
  517.  
  518. END /* PS_get_layer */
  519.  
  520.  
  521. void  PS_get_learn_values(ptr_file, ptr_layer_spec)
  522. FILE        *ptr_file;
  523. Layer_spec  *ptr_layer_spec;
  524. /*
  525. ----------------------------------------------------------------------
  526.   This routine checks for the optional learning rate, scale, and momentum
  527.   specifications for a given layer.  It is called only from the
  528.   "PS_get_nodes" routine. All three of these values will default to 0 
  529.   unless specified in the file. A zero value for either a learn_base or
  530.   the momentum is considered as an "unknown" value when the layer is 
  531.   allocated. At a later point, the user is prompted for learning rates
  532.   and momentum values if none exist in the file.
  533.   NOTE: since these three commands are optional, this routine has no way
  534.   of knowing when to stop checking except by detecting when its gone
  535.   too far. That is, you only know that there are no X and Y dimensions
  536.   specified when you (1) read LAYER, (2) read TARGET, or (3) hit EOF.
  537.   Thus, you will end up reading some command which may be needed in
  538.   another checking routine.  As a result, this routine sets the 
  539.   "use_last_command" flag to TRUE before it exits.
  540. ----------------------------------------------------------------------
  541. */
  542. BEGIN
  543.    int    temp, PS_get_command(), PS_range_check();
  544.    float  num;
  545.    void   PS_print_command();
  546.  
  547.    /*------------------------------------*/
  548.    /* first set the default learning and */
  549.    /* momentum values. These will be     */
  550.    /* used unless overwritten below.     */
  551.    /*------------------------------------*/
  552.    ptr_layer_spec->learn_base  = global_learn_base;
  553.    ptr_layer_spec->momentum    = global_momentum;
  554.    
  555.    /*----------------------------------------------------------*/
  556.    /* the scale factor is undefined ONLY if no global learning */
  557.    /* rate exists. Else, 0 = no scaling unless overwritten     */
  558.    /*----------------------------------------------------------*/
  559.    if (global_learn_base == UNDEFINED)
  560.       ptr_layer_spec->learn_scale = UNDEFINED;
  561.    else ptr_layer_spec->learn_scale = 0;
  562.    
  563.  
  564.    /*--------------------------------------------*/
  565.    /* read in commands until NODES command found */
  566.    /*--------------------------------------------*/
  567.    temp = PS_get_command(ptr_file, &num);
  568.    while (temp != NODES) BEGIN
  569.       if (temp == EOF) BEGIN
  570.          ptr_layer_spec->status = EOF;
  571.          break;
  572.       ENDIF
  573.       if (temp == SCALE_FACTOR) BEGIN
  574.          if (PS_range_check(GELE(num, 0, SCALE_MAX)) == OK)
  575.             ptr_layer_spec->learn_scale = num;
  576.       ENDIF
  577.       else if (temp == LEARN_RATE) BEGIN
  578.          if (PS_range_check(GTLE(num, 0, LEARN_MAX)) == OK)
  579.             ptr_layer_spec->learn_base = num;
  580.       ENDELSE
  581.       else if (temp == MOMENTUM) BEGIN
  582.          if (PS_range_check(GELE(num, 0, MOMENTUM_MAX)) == OK)
  583.             ptr_layer_spec->momentum = num;
  584.       ENDELSE
  585.       else BEGIN
  586.          sprintf(IO_str, "\n*** WARNING: spurious ");
  587.          IO_print(0);
  588.          PS_print_command(temp);
  589.          sprintf(IO_str, " command found in the middle of a LAYER specification.");
  590.          IO_print(0);
  591.          sprintf(IO_str, "\nCommand ignored.");
  592.          IO_print(0);
  593.       ENDELSE
  594.       temp = PS_get_command(ptr_file, &num);
  595.    ENDWHILE
  596.    use_last_command = TRUE;
  597.  
  598. END /* PS_get_learn_values */
  599.  
  600.  
  601. void  PS_get_nodes(ptr_file, ptr_layer_spec)
  602. FILE        *ptr_file;
  603. Layer_spec  *ptr_layer_spec;
  604. /*
  605. ----------------------------------------------------------------------
  606.   The NODES section of a layer specification is a non-optional delimeter
  607.   of how many nodes should be allocated to the layer.  It does have two
  608.   optional arguments, X-DIMENSION and Y-DIMENSION, which can be used to
  609.   determine the geometry of the layer. Furthermore, one can make the
  610.   assumption that this routine is ONLY called by the PS_get_layer routine
  611.   above. Thus the last command read by the parser is the LAYER command
  612.   and we can continue reading PAST that command.
  613.   This routine operates as follows. First, a loop is entered which continues
  614.   until a NODES command is reached or the EOF is found.  If a successful
  615.   NODES command is found, then its value is recorded and the routine
  616.   'PS_get_node_dimensions' is called to check for the optional X and
  617.   Y dimension specifications.
  618. ----------------------------------------------------------------------
  619. */
  620. BEGIN
  621.    void   PS_get_node_dimensions(), PS_print_command();
  622.    float  num;
  623.    int    temp, PS_get_command(), PS_int_check(), PS_range_check();
  624.  
  625.    temp = PS_get_command(ptr_file, &num);
  626.    while (TRUE) BEGIN
  627.       if (temp == EOF) BEGIN
  628.          sprintf(IO_str, "\n*** ERROR: could not find NODES specification for Layer %d",
  629.                 ptr_layer_spec->ID);
  630.          IO_print(0);
  631.          ptr_layer_spec->status = ERROR;
  632.          break;
  633.       ENDIF
  634.       if ( (temp == NODES)
  635.            && (PS_int_check(num) == OK)
  636.            && (PS_range_check(GTLE(num, 0, MAX_NODES)) == OK) ) 
  637.          break;
  638.       else if (temp == LAYER) BEGIN
  639.          sprintf(IO_str, "\n*** Warning: No NODES specification provided for LAYER %d",
  640.                 ptr_layer_spec->ID);
  641.          IO_print(0);
  642.          sprintf(IO_str, "\nLayer %d ignored", ptr_layer_spec->ID);
  643.          IO_print(0);
  644.          ptr_layer_spec->ID = (int)num;
  645.       ENDELSE
  646.       else BEGIN
  647.          sprintf(IO_str, "\n*** WARNING: spurious ");
  648.          IO_print(0);
  649.          PS_print_command(temp);
  650.          sprintf(IO_str, " command found before NODES specification.");
  651.          IO_print(0);
  652.          sprintf(IO_str, "\nCommand ignored.");
  653.          IO_print(0);
  654.       ENDELSE
  655.       temp = PS_get_command(ptr_file, &num);
  656.    ENDWHILE
  657.  
  658.    if (ptr_layer_spec->status == OK) BEGIN
  659.       ptr_layer_spec->num_nodes = num;
  660.       PS_get_node_dimensions(ptr_file, ptr_layer_spec);
  661.    ENDIF
  662.    
  663. END /* PS_get_nodes */
  664.  
  665.  
  666. void  PS_get_node_dimensions(ptr_file, ptr_layer_spec)
  667. FILE        *ptr_file;
  668. Layer_spec  *ptr_layer_spec;
  669. /*
  670. ----------------------------------------------------------------------
  671.   This routine checks for the optional X and Y dimension specifications
  672.   for a given layer's NODES specification.  It is called only from the
  673.   "PS_get_nodes" routine. The X and Y dimension specs are optional and 
  674.   will default as follows. If neither is specified, then the X dimension 
  675.   is set to the NODES value and the Y dimension is set to 1. If only 
  676.   one dimension is set, then the other dimension is set to 1. In any 
  677.   event, the product of the X and Y dimensions is found and compared 
  678.   to the NODES value. If they are not equal and error is sighted.
  679.   NOTE: since these two commands are optional, this routine has no way
  680.   of knowing when to stop checking except by detecting when its gone
  681.   too far. That is, you only know that there are no X and Y dimensions
  682.   specified when you (1) read LAYER, (2) read TARGET, (3) hit EOF or
  683.   (4) read a LEARN-RATE, SCALE-FACTOR, or MOMENTUM command. Thus, you 
  684.   will end up reading some command which may be needed in another 
  685.   checking routine.  As a result, this routine sets the "use_last_command"
  686.   flag to TRUE before it exits.
  687. ----------------------------------------------------------------------
  688. */
  689. BEGIN
  690.    int    temp, PS_get_command(), PS_int_check(), PS_range_check();
  691.    float  num;
  692.    void   PS_print_command();
  693.  
  694.    ptr_layer_spec->X_dim = -1;      /* initialize dimensions to -1 */
  695.    ptr_layer_spec->Y_dim = -1;
  696.  
  697.    /*---------------------------------------------------------------------*/
  698.    /* read in commands until LAYER or TARGET, checking for X,Y dimensions */
  699.    /*---------------------------------------------------------------------*/
  700.    temp = PS_get_command(ptr_file, &num);
  701.    while ((temp != LAYER)
  702.           && (temp != TARGET)) BEGIN
  703.       if (temp == EOF) BEGIN
  704.          ptr_layer_spec->status = EOF;
  705.          break;
  706.       ENDIF
  707.       if (temp == X_DIMENSION) BEGIN
  708.          if ( (PS_int_check(num) == OK)
  709.               &&(PS_range_check(GTLE(num, 0, MAX_NODES)) == OK) )
  710.             ptr_layer_spec->X_dim = num;
  711.       ENDIF
  712.       else if (temp == Y_DIMENSION) BEGIN
  713.          if ( (PS_int_check(num) == OK)
  714.               &&(PS_range_check(GTLE(num, 0, MAX_NODES)) == OK) )
  715.             ptr_layer_spec->Y_dim = num;
  716.       ENDELSE
  717.       else BEGIN
  718.          sprintf(IO_str, "\n*** WARNING: spurious ");
  719.          IO_print(0);
  720.          PS_print_command(temp);
  721.          sprintf(IO_str, " command found in the middle of a NODES specification.");
  722.          IO_print(0);
  723.          sprintf(IO_str, "\nCommand ignored.");
  724.          IO_print(0);
  725.       ENDELSE
  726.       temp = PS_get_command(ptr_file, &num);
  727.    ENDWHILE
  728.  
  729.    /*----------------------------------------------------*/
  730.    /* Set default values of X_dim and Y_dim if necessary */
  731.    /*----------------------------------------------------*/
  732.    if ((ptr_layer_spec->X_dim == -1) && (ptr_layer_spec->Y_dim == -1)) BEGIN
  733.       ptr_layer_spec->X_dim = ptr_layer_spec->num_nodes;
  734.       ptr_layer_spec->Y_dim = 1;
  735.    ENDIF
  736.    else BEGIN
  737.       if (ptr_layer_spec->X_dim == -1) ptr_layer_spec->X_dim = 1;
  738.       if (ptr_layer_spec->Y_dim == -1) ptr_layer_spec->Y_dim = 1;
  739.    ENDELSE
  740.  
  741.    if ((ptr_layer_spec->X_dim * ptr_layer_spec->Y_dim)
  742.        != ptr_layer_spec->num_nodes) BEGIN
  743.       sprintf(IO_str, "\n*** ERROR: X,Y dimensions inconsistent with the number of nodes in layer %d",
  744.              ptr_layer_spec->ID);
  745.       IO_print(0);
  746.       ptr_layer_spec->status = ERROR;
  747.    ENDIF
  748.    use_last_command = TRUE;
  749.  
  750. END /* PS_get_node_dimensions */
  751.  
  752.  
  753. void  PS_get_target(ptr_file, ptr_layer_spec)
  754. FILE        *ptr_file;
  755. Layer_spec  *ptr_layer_spec;
  756. /*
  757. ----------------------------------------------------------------------
  758.   This routine must search for any number of target specs (ie, one or
  759.   more).
  760.  
  761.   layer-spec   :== LAYER  node-spec  {target-spec}
  762.   node-spec    :== NODES  {X-DIMENSION}  {Y-DIMENSION}
  763.   target-spec  :== TARGET  {pattern-spec} {target-spec}
  764.   pattern-spec :== PATTERN-X-DIMENSION  PATTERN-Y-DIMENSION  {X-OVERLAP}
  765.                    {Y-OVERLAP}
  766. ----------------------------------------------------------------------
  767. */
  768. BEGIN
  769.    void   PS_get_pattern(), PS_print_command();
  770.    float  num;
  771.    int    temp, target_count, PS_get_command(), PS_int_check(), 
  772.           PS_range_check();
  773.  
  774.    target_count = 0;
  775.    temp = PS_get_command(ptr_file, &num);
  776.    while ((temp != LAYER) && (ptr_layer_spec->status == 1)) BEGIN
  777.       if (temp == EOF) BEGIN
  778.          ptr_layer_spec->status = EOF;
  779.          break;
  780.       ENDIF
  781.       else if (temp == TARGET) BEGIN
  782.          if ( (PS_int_check(num) == OK)
  783.               && (PS_range_check(GELE(num, 0, MAX_LAYERS)) == OK) ) BEGIN
  784.             ptr_layer_spec->targets[target_count][0] = (int16)num;
  785.             ptr_layer_spec->targets[target_count][1] = (int16)0;
  786.             ptr_layer_spec->targets[target_count][2] = (int16)0;
  787.             ptr_layer_spec->targets[target_count][3] = (int16)0;
  788.             ptr_layer_spec->targets[target_count][4] = (int16)0;
  789.             PS_get_pattern(ptr_file, ptr_layer_spec, target_count);
  790.             target_count++;
  791.          ENDIF
  792.       ENDELSE
  793.       else BEGIN
  794.          sprintf(IO_str, "\n*** WARNING: spurious ");
  795.          IO_print(0);
  796.          PS_print_command(temp);
  797.          sprintf(IO_str, " command found in the middle of a TARGET specification.");
  798.          IO_print(0);
  799.          sprintf(IO_str, "\nCommand ignored.");
  800.          IO_print(0);
  801.       ENDELSE
  802.       temp = PS_get_command(ptr_file, &num);
  803.    ENDWHILE
  804.    ptr_layer_spec->num_targets = target_count;
  805.    use_last_command = TRUE;
  806.  
  807. END /* PS_get_target */
  808.  
  809.  
  810. void  PS_get_pattern(ptr_file, ptr_layer_spec, target_index)
  811. FILE        *ptr_file;
  812. Layer_spec  *ptr_layer_spec;
  813. int         target_index;
  814. /*
  815. ----------------------------------------------------------------------
  816.   The entire pattern spec is optional. However, if present it looks
  817.   like:
  818.  
  819.   pattern-spec :== PATTERN-X-DIMENSION PATTERN-Y-DIMENSION 
  820.                    {X-OVERLAP} {Y-OVERLAP}
  821.   
  822.   Reading this specification is achieved in a three step process. First,
  823.   the PATTERN-X-DIMENSION command is looked for, if a LAYER or TARGET 
  824.   command doesn't appear first. Once it is found, step two is to search
  825.   for the PATTERN-Y-DIMENSION.  If it is not present, that is an error
  826.   (you can't have a half-specified pattern). The third step consists 
  827.   of a while loop to search for the optional OVERLAP dimensions which
  828.   will default to 0 if they are not present. Finally, if a pattern is
  829.   specified, then the end of its specification will occur on a TARGET
  830.   or LAYER command, thus the "use_last_command" flag is set to TRUE.
  831. ----------------------------------------------------------------------
  832. */
  833. BEGIN
  834.    int    temp, PS_get_command(), PS_int_check(), PS_range_check();
  835.    float  num;
  836.    void   PS_print_command();
  837.  
  838.    /*---------------------------------------------------------*/
  839.    /* Step 1: find the PATTERN-X-DIMENSION command if present */
  840.    /*---------------------------------------------------------*/
  841.    temp = PS_get_command(ptr_file, &num);
  842.    if (temp == EOF) 
  843.       ptr_layer_spec->status = EOF;
  844.    else if ((temp == LAYER) || (temp == TARGET))
  845.       use_last_command = TRUE;
  846.    else if (temp != PATTERN_X_DIM) BEGIN
  847.       sprintf(IO_str, "\n*** ERROR: found spurious ");
  848.       IO_print(0);
  849.       PS_print_command(temp);
  850.       sprintf(IO_str, " command in the middle of a PATTERN specification.");
  851.       IO_print(0);
  852.       sprintf(IO_str, "\nExpected a PATTERN-X-DIMENSION command.");
  853.       IO_print(0);
  854.       ptr_layer_spec->status = ERROR;
  855.    ENDELSE
  856.    
  857.    /*----------------------------------------------------------------------*/
  858.    /* Step 2: if PATTERN-X-DIMENSION command found, search for Y dimension */
  859.    /*----------------------------------------------------------------------*/
  860.    else BEGIN
  861.       if ( (PS_int_check(num) == OK)
  862.            && PS_range_check(GTLE(num, 0, MAX_NODES) == OK) )
  863.          ptr_layer_spec->targets[target_index][1] = (int16)num;  /* pattern_x_dim */
  864.       temp = PS_get_command(ptr_file, &num);
  865.       if (temp != PATTERN_Y_DIM) BEGIN                       /* error if no y dim */
  866.          sprintf(IO_str, "\n*** ERROR: Incomplete pattern dimension specification.");
  867.          IO_print(0);
  868.          sprintf(IO_str, "\nExpected a PATTERN-Y-DIMENSION command.");
  869.          IO_print(0);
  870.          ptr_layer_spec->status = ERROR;
  871.       ENDIF
  872.       else BEGIN
  873.          if ( (PS_int_check(num) == OK)
  874.               && PS_range_check(GTLE(num, 0, MAX_NODES) == OK) )
  875.             ptr_layer_spec->targets[target_index][2] = (int16)num;
  876.          temp = PS_get_command(ptr_file, &num);
  877.          
  878.          /*-------------------------------------------------------------*/
  879.          /* Step 3: once both dimensions are found, search for OVERLAPs */
  880.          /*-------------------------------------------------------------*/
  881.          while ((temp != LAYER) && (temp != TARGET)) BEGIN
  882.             if (temp == EOF) BEGIN
  883.                ptr_layer_spec->status = EOF;
  884.                break;
  885.             ENDIF
  886.             else if (temp == X_OVERLAP) BEGIN
  887.                if ( (PS_int_check(num) == OK)
  888.                     && PS_range_check(GTLE(num, 0, MAX_NODES) == OK) )
  889.                   ptr_layer_spec->targets[target_index][3] = (int16)num;
  890.             ENDELSE
  891.             else if (temp == Y_OVERLAP) BEGIN
  892.                 if ( (PS_int_check(num) == OK)
  893.                      && PS_range_check(GTLE(num, 0, MAX_NODES) == OK) )
  894.                   ptr_layer_spec->targets[target_index][4] = (int16)num;
  895.             ENDELSE
  896.             else BEGIN
  897.                sprintf(IO_str, "\n*** WARNING: spurious ");
  898.                IO_print(0);
  899.                PS_print_command(temp);
  900.                sprintf(IO_str, " command found in the middle of a pattern OVERLAP specification.");
  901.                IO_print(0);
  902.                sprintf(IO_str, "\nCommand ignored.");
  903.                IO_print(0);
  904.             ENDELSE
  905.             temp = PS_get_command(ptr_file, &num);
  906.          ENDWHILE
  907.          use_last_command = TRUE;
  908.       ENDELSE
  909.    ENDELSE
  910.  
  911. END /* PS_get_pattern */
  912.  
  913.  
  914. int  PS_get_command(ptr_file, ptr_data)
  915. FILE   *ptr_file;
  916. float  *ptr_data;
  917. /*
  918. ----------------------------------------------------------------------
  919.  Given a pointer to an input file, this guy will read through the
  920.   file line by line, until a valid command is reached.  Since each
  921.   line of the input is to have at most 1 command, only the first 
  922.   command in a line will be read; any others will be ignored. The 
  923.   set of valid commands is defined by the BNF for parsing a layer
  924.   specification (see netio.h and comments under 'PS_get_layer').
  925.   A return code is given which depends upon the command found. These
  926.   return codes are defined as constants in the netio.h file. Since
  927.   this routine has no idea of syntax or semantics, it cannot tell
  928.   whether or not the last command it read was actually used, or
  929.   simply served as a delimiter for the BNF. Consequently, this
  930.   routine must be told whether or not to reuse the last command 
  931.   which was found. This information is kept in a global variable
  932.   (for convenience) called "use_last_command" and is set or reset
  933.   by the 'PS_get_layer' and 'PS_reset_for_layer_parse' routines.
  934.  Aside from the return value specified above, any data which accompanies
  935.   the command is returned via the 'ptr_data' parameter which is passed
  936.   in from the calling routine.
  937. ----------------------------------------------------------------------
  938.  9-7-89 Note that I have made the "last_str" variable global. I did this
  939.   to enable better error messages. By having access to the last command
  940.   read by the system, I can print out a message which will be more 
  941.   meaningful to the user. A global variable seems the best way to make
  942.   the last command available to many routines.
  943. ----------------------------------------------------------------------
  944. */
  945. BEGIN
  946.    static char  temp_str[MAX_LINE_SIZE];
  947.  
  948.    if (use_last_command == FALSE)
  949.       if (fgets(last_str, MAX_LINE_SIZE, ptr_file) == NULL)
  950.          return(EOF);
  951.    use_last_command = FALSE;     /* reset flag so reuse only ONCE */
  952.  
  953.    while (TRUE) BEGIN
  954.       if (sscanf(last_str, "%s : %f", temp_str, ptr_data) == 2) BEGIN
  955.          if (strcmp(temp_str, "TARGET") == 0) 
  956.             return(TARGET);
  957.          if (strcmp(temp_str, "LAYER") == 0)
  958.             return(LAYER);
  959.          if (strcmp(temp_str, "NODES") == 0) 
  960.             return(NODES);
  961.          if (strcmp(temp_str, "X-DIMENSION") == 0) 
  962.             return(X_DIMENSION);
  963.          if (strcmp(temp_str, "Y-DIMENSION") == 0) 
  964.             return(Y_DIMENSION);
  965.          if (strcmp(temp_str, "LEARN-RATE") == 0) 
  966.             return(LEARN_RATE);
  967.          if (strcmp(temp_str, "GLOBAL-LEARN-RATE") == 0) 
  968.             return(GLOBAL_LEARN_RATE);
  969.          if (strcmp(temp_str, "SCALE-FACTOR") == 0) 
  970.             return(SCALE_FACTOR);
  971.          if (strcmp(temp_str, "GLOBAL-MOMENTUM") == 0) 
  972.             return(GLOBAL_MOMENTUM);
  973.          if (strcmp(temp_str, "MOMENTUM") == 0) 
  974.             return(MOMENTUM);
  975.          if (strcmp(temp_str, "PATTERN-X-DIMENSION") == 0) 
  976.             return(PATTERN_X_DIM);
  977.          if (strcmp(temp_str, "PATTERN-Y-DIMENSION") == 0) 
  978.             return(PATTERN_Y_DIM);
  979.          if (strcmp(temp_str, "X-OVERLAP") == 0) 
  980.             return(X_OVERLAP);
  981.          if (strcmp(temp_str, "Y-OVERLAP") == 0) 
  982.             return(Y_OVERLAP);
  983.       ENDIF
  984.  
  985.       if (fgets(last_str, MAX_LINE_SIZE, ptr_file) == NULL)
  986.          return(EOF);
  987.    ENDWHILE
  988.  
  989. END /* PS_get_command */
  990.  
  991.  
  992. int  PS_range_check(comparison)
  993. int   comparison;
  994. /*
  995. ----------------------------------------------------------------------
  996.   Checks the results given by comparison and determines whether or not
  997.   to print out a message. If comparison == 1, then the range check was
  998.   OK, otherwise, the command had a number out of range. 
  999.   NOTE: this routine uses the "last_str" global variable which holds
  1000.   the last command read in to NETS. This saves me the trouble of passing
  1001.   the bloody thing around.
  1002. ----------------------------------------------------------------------
  1003. */
  1004. BEGIN
  1005.    if (comparison) 
  1006.       return(OK);
  1007.    sprintf(IO_str, "\n *** ERROR: the command:\n %s has a value which is out of range",
  1008.            last_str);
  1009.    IO_print(0);
  1010.    sprintf(IO_str, "\n Command ignored.");
  1011.    IO_print(0);
  1012.    return(ERROR);
  1013.    
  1014. END /* PS_range_check */
  1015.  
  1016.  
  1017. int  PS_int_check(num)
  1018. float  num;
  1019. /*
  1020. ----------------------------------------------------------------------
  1021.   Some of the commands in NETS need integer arguments. This routine is
  1022.   called to check that the number associated with a command was indeed
  1023.   an integer. If not, a message is printed and ERROR is returned.
  1024.   NOTE: as with the PS_range_check routine, this guy make use of the
  1025.   "last_str" global variable which is updated by PS_get_command to print
  1026.   the last command to the user.
  1027. ----------------------------------------------------------------------
  1028. */
  1029. BEGIN
  1030.    if (num == ((float) ((int) num)) )
  1031.       return(OK);
  1032.    
  1033.    sprintf(IO_str, "\n *** ERROR: the command:\n %s should have an INTEGER value",
  1034.            last_str);
  1035.    IO_print(0);
  1036.    sprintf(IO_str, "\n Command ignored.");
  1037.    IO_print(0);
  1038.    return(ERROR);
  1039.    
  1040. END /* PS_int_check */
  1041.  
  1042.  
  1043. void  PS_print_command(command)
  1044. int  command;
  1045. /*
  1046. ----------------------------------------------------------------------
  1047.   Just a common routine for all of the layer parsing routines which 
  1048.   can be used to print out parts of error messages.
  1049. ----------------------------------------------------------------------
  1050. */
  1051. BEGIN
  1052.    switch (command) BEGIN
  1053.       case LAYER : BEGIN
  1054.          sprintf(IO_str, "LAYER");
  1055.          IO_print(0);
  1056.          break;
  1057.       ENDCASE
  1058.       case NODES : BEGIN
  1059.          sprintf(IO_str, "NODES");
  1060.          IO_print(0);
  1061.          break;
  1062.       ENDCASE
  1063.       case X_DIMENSION : BEGIN
  1064.          sprintf(IO_str, "X-DIMENSION");
  1065.          IO_print(0);
  1066.          break;
  1067.       ENDCASE
  1068.       case Y_DIMENSION : BEGIN
  1069.          sprintf(IO_str, "Y-DIMENSION");
  1070.          IO_print(0);
  1071.          break;
  1072.       ENDCASE
  1073.       case LEARN_RATE : BEGIN
  1074.          sprintf(IO_str, "LEARN-RATE");
  1075.          IO_print(0);
  1076.          break;
  1077.       ENDCASE
  1078.       case SCALE_FACTOR : BEGIN
  1079.          sprintf(IO_str, "SCALE-FACTOR");
  1080.          IO_print(0);
  1081.          break;
  1082.       ENDCASE
  1083.       case MOMENTUM : BEGIN
  1084.          sprintf(IO_str, "MOMENTUM");
  1085.          IO_print(0);
  1086.          break;
  1087.       ENDCASE
  1088.       case TARGET : BEGIN
  1089.          sprintf(IO_str, "TARGET");
  1090.          IO_print(0);
  1091.          break;
  1092.       ENDCASE
  1093.       case PATTERN_X_DIM : BEGIN
  1094.          sprintf(IO_str, "PATTERN-X-DIMENSION");
  1095.          IO_print(0);
  1096.          break;
  1097.       ENDCASE
  1098.       case PATTERN_Y_DIM : BEGIN
  1099.          sprintf(IO_str, "PATTERN-Y-DIMENSION");
  1100.          IO_print(0);
  1101.          break;
  1102.       ENDCASE
  1103.       case X_OVERLAP : BEGIN
  1104.          sprintf(IO_str, "X-OVERLAP");
  1105.          IO_print(0);
  1106.          break;
  1107.       ENDCASE
  1108.       case Y_OVERLAP : BEGIN
  1109.          sprintf(IO_str, "Y-OVERLAP");
  1110.          IO_print(0);
  1111.          break;
  1112.       ENDCASE
  1113.       default : break;
  1114.    ENDSWITCH
  1115.  
  1116. END /* PS_print_command */
  1117.  
  1118.  
  1119. int  PS_parse_iopairs(file_name, sum)
  1120. char  file_name[];
  1121. int   sum;
  1122. /*
  1123. ----------------------------------------------------------------------
  1124.  This guy is called from "PA_setup_iopairs" to do most of the work in  
  1125.   setting up the io pairs for teaching the system.  The basic idea    
  1126.   is to read through the file (represented by "filename" above) which 
  1127.   specifies the io-pairs and sift through any comments, creating a    
  1128.   streamlined version of the io-pairs (in Sint format) which will be  
  1129.   used for the actual training.  Now, you might be wondering why we   
  1130.   don't just read in the io-pairs and store them in memory since that 
  1131.   would be a much faster approach.  The problem is that the number of 
  1132.   io-pairs can get enormous, which would put too great a burden on    
  1133.   the RAM we were attempting to use.  A more practical approach is to 
  1134.   convert the io-pairs into the exact format we need (Sints) and then 
  1135.   store them into a temporary file in a convenient format.  Then,     
  1136.   when we do our training, we can mass-read a large number of the io- 
  1137.   pairs into a buffer, and train from the buffer.  The result is a    
  1138.   compromise between the ideal case of storing all of the io-pairs in 
  1139.   memory, and the worst case of having to read all the io-pairs from  
  1140.   disk one byte at a time.    
  1141.                                         
  1142.  Returns the number of io pairs successfully read in and translated.  
  1143.   ERROR is returned if there are any errors during processing.           
  1144.  
  1145.  Note that this routine depends upon "the_buffer", "line_count", and  
  1146.   "last_char", all of which are variables global to netio.c           
  1147. ----------------------------------------------------------------------
  1148. */
  1149. BEGIN
  1150.    int    PS_check_items(), PS_skip_tokens(), PS_get_token();
  1151.    FILE   *fp_input, *fp_output;
  1152.    int    list_count, item_count, STATUS; 
  1153.    char   next_token[MAX_WORD_SIZE];
  1154.    float  fnum;
  1155.  
  1156.    fp_input  = fopen(file_name, "rt");
  1157.    fp_output = PA_open_binary("workfile.net", WRITE_MODE); 
  1158.  
  1159.    STATUS = OK;
  1160.    list_count = 0;
  1161.    while (PS_skip_tokens(fp_input, "(" ) == OK) BEGIN      /* more lists */
  1162.       list_count++;                                  /* incr # of lists  */
  1163.       item_count = 0;                                /* reset num items  */
  1164.       while (PS_get_token(fp_input, next_token) == OK) BEGIN
  1165.          if (strcmp(next_token, ")" ) == 0)      /* items++ til ")"  */
  1166.             break;                              
  1167.          if (sscanf(next_token, "%f", &fnum) == OK) BEGIN
  1168.             if (PA_put_to_workfile(fp_output, C_float_to_Sint(fnum)) == ERROR)
  1169.                return(ERROR);
  1170.             item_count++;
  1171.          ENDIF
  1172.       ENDWHILE
  1173.       STATUS = PS_check_items(item_count, sum, list_count);
  1174.    ENDWHILE
  1175.  
  1176.    fclose(fp_input);
  1177.    PA_flush(fp_output);
  1178.    fclose(fp_output);
  1179.    if ((STATUS == ERROR) || (list_count == 0))
  1180.       return(ERROR);
  1181.    else return(list_count);
  1182.  
  1183. END /* PS_parse_iopairs */
  1184.  
  1185.  
  1186. int  PS_check_items(num_items, max_items, list_count)
  1187. int  num_items, max_items, list_count;
  1188. /*
  1189. ----------------------------------------------------------------------
  1190.  A routine to check the number of items counted in an io pair list to 
  1191.   see if that number is equal to the desired length of the list.  If  
  1192.   the 'num_items' is either greater than or less than 'max_items'     
  1193.   (which is the desired length of the io pair) then ERROR is returned  
  1194.   to indicate that an error was found.  Also, to help the user in     
  1195.   finding the error, the current line is also printed to indicate     
  1196.   where the current io pair list ended.  Note that there is a trick to
  1197.   printing out the current line.  The routine 'PS_get_token' counts the  
  1198.   number of newlines, but it does not indicate whether the list was   
  1199.   ended by a newline or by a comment.  If the list was ended by a     
  1200.   comment, then 'PS_get_token' will be waiting on the SAME line as the   
  1201.   end of the list for the next token.  On the other hand, if the io   
  1202.   pair list was ended with a ")" followed by a newline, then the      
  1203.   'PS_get_token' routine will be waiting on the NEXT line.  Thus the     
  1204.   first two lines of this code check that ending condition, and set   
  1205.   the 'end_list' variable accordingly.
  1206.                            
  1207.  Note that the 'list_count' variable is passed in here for printing   
  1208.   purposes only.                                                      
  1209. ----------------------------------------------------------------------
  1210. */
  1211. BEGIN
  1212.    int  end_list;
  1213.  
  1214.    end_list = line_count;                       /* see where list ended */
  1215.    if (last_char == NEWLINE) end_list--;        /* decr if ended w/ nl  */
  1216.    if (num_items > max_items) BEGIN 
  1217.       sprintf(IO_str, "\n*** list number %d is too long ***\n", list_count);
  1218.       IO_print(0);
  1219.       sprintf(IO_str, "    list ends on line %d\n", end_list);
  1220.       IO_print(0);
  1221.       return(ERROR);
  1222.    ENDIF
  1223.    else if (num_items < max_items) BEGIN
  1224.       sprintf(IO_str, "\n*** list number %d is too short ***\n", list_count);
  1225.       IO_print(0);
  1226.       sprintf(IO_str, "    list ends on line %d\n", end_list);
  1227.       IO_print(0);
  1228.       return(ERROR);
  1229.    ENDELSE
  1230.    return(OK);
  1231.  
  1232. END /* PS_check_items */
  1233.  
  1234.  
  1235. int  PS_skip_tokens(fp, token)
  1236. FILE  *fp;
  1237. char  *token;
  1238. /*
  1239. ----------------------------------------------------------------------
  1240.  skips through the tokens in a file until it reaches the value given  
  1241.   by the input 'token'.  Returns ERROR if unsuccessful, otherwise it    
  1242.   returns a OK.
  1243. ----------------------------------------------------------------------
  1244. */
  1245. BEGIN
  1246.    char   temp[MAX_WORD_SIZE];
  1247.    int    PS_get_token();
  1248.    
  1249.    while (PS_get_token(fp, temp) == OK) BEGIN   /* while tokens left in file */
  1250.       if (strcmp(temp, token) == 0)
  1251.          return(OK);
  1252.    ENDWHILE
  1253.    return(ERROR);  
  1254.  
  1255. END /* PS_skip_tokens */
  1256.  
  1257.  
  1258. int  PS_get_token(fp, token)
  1259. FILE  *fp;
  1260. char  *token;
  1261. /*
  1262. ----------------------------------------------------------------------
  1263.  Puts a token in the input parameter 'token' returns ERROR if EOF, 
  1264.   else returns OK. Note that a static integer is used to keep track of
  1265.   whether or not the last character read in should be reused.
  1266. ----------------------------------------------------------------------
  1267. */
  1268. BEGIN
  1269.    static int  use_last_char = FALSE;
  1270.    int  i;
  1271.  
  1272.    i = 0;
  1273.    while (TRUE) BEGIN
  1274.       /*------------------------------------*/
  1275.       /* get the next character; if newline */
  1276.       /* then increment the line count      */
  1277.       /*------------------------------------*/
  1278.       if (use_last_char == TRUE)
  1279.          use_last_char = FALSE;
  1280.       else if ((last_char = getc(fp)) == EOF) 
  1281.          return(ERROR);
  1282.       if (last_char == NEWLINE) line_count++;
  1283.  
  1284.       /*-------------------------------------*/
  1285.       /* if token partially full, then check */
  1286.       /* for end and return; else add char   */
  1287.       /*-------------------------------------*/
  1288.       if (i > 0) BEGIN                               /* inside a word */
  1289.          if ( (last_char == SPACE)
  1290.               || (last_char == TAB)
  1291.               || (last_char == NEWLINE)
  1292.           || (last_char == CLOSE_PAREN)
  1293.           || (last_char == OPEN_PAREN)
  1294.               || (i == MAX_WORD_SIZE - 1) ) BEGIN
  1295.             token[i] = ENDSTRING;
  1296.             /*--------------------------------------------*/
  1297.             /* any single character token checked here    */
  1298.             /* and above; flag set here for reuse of char */
  1299.             /*--------------------------------------------*/
  1300.             if ((last_char == CLOSE_PAREN) || (last_char == OPEN_PAREN))
  1301.                use_last_char = TRUE;
  1302.             return(OK);
  1303.          ENDIF
  1304.          else
  1305.             token[i++] = last_char;
  1306.       ENDIF
  1307.  
  1308.       /*------------------------------------*/
  1309.       /* if at beginning of token, add char */
  1310.       /* if not whitespace; return if paren */
  1311.       /*------------------------------------*/
  1312.       else BEGIN
  1313.          if ( (last_char != SPACE) 
  1314.               && (last_char != TAB) 
  1315.               && (last_char != NEWLINE) ) 
  1316.          token[i++] = last_char;
  1317.      /*-------------------------------*/
  1318.      /* single character tokens found */
  1319.      /* are returned automatically    */
  1320.      /*-------------------------------*/
  1321.          if ( (last_char == OPEN_PAREN)
  1322.           || (last_char == CLOSE_PAREN)) BEGIN
  1323.             token[i] = ENDSTRING;
  1324.             return(OK);
  1325.          ENDIF
  1326.       ENDELSE
  1327.  
  1328.    ENDWHILE
  1329.  
  1330. END /* PS_get_token */
  1331.  
  1332.  
  1333. int  PS_get_float_from_file(fp, ptr_float)
  1334. FILE   *fp;
  1335. float  *ptr_float;
  1336. /*
  1337. ----------------------------------------------------------------------
  1338.   This routine is used for retrieving floating point numbers from some
  1339.   input file (specified by the file pointer "fp"). It is used only
  1340.   during a "query_from_file" request made by the user. In such a 
  1341.   request, inputs to the network are read from a file and mapped onto
  1342.   the input layer.  This routine will read through any file, picking
  1343.   out floating point numbers.  The routine 'N_query_net' makes
  1344.   sure that the right number of foats are read and mapped onto the
  1345.   input layer.
  1346.  
  1347.  Returns OK if a floating point number is successfully loaded into the 
  1348.   'ptr_float' variable, otherwise it returns ERROR. It makes use of the
  1349.   the 'PS_get_token' routine to do all of the dirty work is getting the  
  1350.   input from the file.  Note that he skips over all inputs that are   
  1351.   not floating point.
  1352. ----------------------------------------------------------------------
  1353. */
  1354. BEGIN
  1355.    static char  in_string[MAX_LINE_SIZE];
  1356.    int          PS_get_token();
  1357.  
  1358.    while (TRUE) BEGIN
  1359.       if (PS_get_token(fp, in_string) == ERROR)
  1360.          return(ERROR);
  1361.       if (sscanf(in_string, "%f", ptr_float) == 1)
  1362.          return(OK);
  1363.    ENDWHILE
  1364.  
  1365. END /* PS_get_float_from_file */
  1366.